home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / Src / Ch10 / Mand.frm < prev    next >
Text File  |  1999-06-09  |  15KB  |  542 lines

  1. VERSION 5.00
  2. Object = "{F9043C88-F6F2-101A-A3C9-08002B2F49FB}#1.2#0"; "COMDLG32.OCX"
  3. Begin VB.Form frmMand 
  4.    Caption         =   "Mand"
  5.    ClientHeight    =   3810
  6.    ClientLeft      =   2370
  7.    ClientTop       =   1320
  8.    ClientWidth     =   3810
  9.    LinkTopic       =   "Form1"
  10.    PaletteMode     =   1  'UseZOrder
  11.    ScaleHeight     =   254
  12.    ScaleMode       =   3  'Pixel
  13.    ScaleWidth      =   254
  14.    Begin MSComDlg.CommonDialog dlgFile 
  15.       Left            =   120
  16.       Top             =   120
  17.       _ExtentX        =   847
  18.       _ExtentY        =   847
  19.       _Version        =   393216
  20.    End
  21.    Begin VB.PictureBox picCanvas 
  22.       AutoRedraw      =   -1  'True
  23.       BackColor       =   &H00000000&
  24.       Height          =   3810
  25.       Left            =   0
  26.       MousePointer    =   2  'Cross
  27.       ScaleHeight     =   250
  28.       ScaleMode       =   3  'Pixel
  29.       ScaleWidth      =   250
  30.       TabIndex        =   0
  31.       Top             =   0
  32.       Width           =   3810
  33.    End
  34.    Begin VB.Menu mnuFile 
  35.       Caption         =   "&File"
  36.       Begin VB.Menu mnuFileSaveAs 
  37.          Caption         =   "&Save As..."
  38.          Shortcut        =   ^A
  39.       End
  40.    End
  41.    Begin VB.Menu mnuScaleMnu 
  42.       Caption         =   "&Scale"
  43.       Begin VB.Menu mnuScale 
  44.          Caption         =   "x&2"
  45.          Index           =   2
  46.       End
  47.       Begin VB.Menu mnuScale 
  48.          Caption         =   "x&4"
  49.          Index           =   4
  50.       End
  51.       Begin VB.Menu mnuScale 
  52.          Caption         =   "x&8"
  53.          Index           =   8
  54.       End
  55.       Begin VB.Menu mnuScaleFull 
  56.          Caption         =   "&Full Scale"
  57.       End
  58.    End
  59.    Begin VB.Menu mnuOpt 
  60.       Caption         =   "&Options"
  61.       Begin VB.Menu mnuOptOptions 
  62.          Caption         =   "&Set Options"
  63.       End
  64.    End
  65.    Begin VB.Menu mnuMovie 
  66.       Caption         =   "&Movie"
  67.       Begin VB.Menu mnuMovieCreate 
  68.          Caption         =   "&Create Movie..."
  69.       End
  70.    End
  71. End
  72. Attribute VB_Name = "frmMand"
  73. Attribute VB_GlobalNameSpace = False
  74. Attribute VB_Creatable = False
  75. Attribute VB_PredeclaredId = True
  76. Attribute VB_Exposed = False
  77. Option Explicit
  78.  
  79. Private m_DrawingBox As Boolean
  80. Private m_StartX As Single
  81. Private m_StartY As Single
  82. Private m_CurX As Single
  83. Private m_CurY As Single
  84.  
  85. Private m_Xmin As Single
  86. Private m_Xmax As Single
  87. Private m_Ymin As Single
  88. Private m_Ymax As Single
  89.  
  90. Public MaxIterations As Integer
  91.  
  92. Public NumColors As Integer
  93. Private m_Colors() As Long
  94.  
  95. Private Const MIN_X = -2.2
  96. Private Const MAX_X = 1
  97. Private Const MIN_Y = -1.2
  98. Private Const MAX_Y = 1.2
  99.  
  100. ' Return this color's value.
  101. Property Get Color(ByVal Index As Integer) As Long
  102.     Color = m_Colors(Index)
  103. End Property
  104.  
  105. ' Add this color to the list.
  106. Public Sub AddColor(ByVal new_color As Long)
  107.     NumColors = NumColors + 1
  108.     ReDim Preserve m_Colors(1 To NumColors)
  109.     m_Colors(NumColors) = new_color
  110. End Sub
  111. ' Adjust the aspect ratio of the selected
  112. ' coordinates so they fit the window properly.
  113. Private Sub AdjustAspect()
  114. Dim want_aspect As Single
  115. Dim picCanvas_aspect As Single
  116. Dim hgt As Single
  117. Dim wid As Single
  118. Dim mid As Single
  119.  
  120.     want_aspect = (m_Ymax - m_Ymin) / (m_Xmax - m_Xmin)
  121.     picCanvas_aspect = picCanvas.ScaleHeight / picCanvas.ScaleWidth
  122.     If want_aspect > picCanvas_aspect Then
  123.         ' The selected area is too tall and thin.
  124.         ' Make it wider.
  125.         wid = (m_Ymax - m_Ymin) / picCanvas_aspect
  126.         mid = (m_Xmin + m_Xmax) / 2
  127.         m_Xmin = mid - wid / 2
  128.         m_Xmax = mid + wid / 2
  129.     Else
  130.         ' The selected area is too short and wide.
  131.         ' Make it taller.
  132.         hgt = (m_Xmax - m_Xmin) * picCanvas_aspect
  133.         mid = (m_Ymin + m_Ymax) / 2
  134.         m_Ymin = mid - hgt / 2
  135.         m_Ymax = mid + hgt / 2
  136.     End If
  137. End Sub
  138.  
  139.  
  140. ' Draw the Mandelbrot set.
  141. Private Sub DrawMandelbrot()
  142. ' Work until the magnitude squared > 4.
  143. Const MAX_MAG_SQUARED = 4
  144.  
  145. Dim pixels() As RGBTriplet
  146. Dim bits_per_pixel As Integer
  147. Dim wid As Long
  148. Dim hgt As Long
  149. Dim clr As Long
  150. Dim i As Integer
  151. Dim j As Integer
  152. Dim ReaC As Double
  153. Dim ImaC As Double
  154. Dim dReaC As Double
  155. Dim dImaC As Double
  156. Dim ReaZ As Double
  157. Dim ImaZ As Double
  158. Dim ReaZ2 As Double
  159. Dim ImaZ2 As Double
  160. Dim r As Integer
  161. Dim b As Integer
  162. Dim g As Integer
  163.  
  164.     picCanvas.Line (0, 0)-(picCanvas.ScaleWidth, picCanvas.ScaleHeight), vbBlack, BF
  165.     DoEvents
  166.  
  167.     ' Get the image's pixels.
  168.     GetBitmapPixels picCanvas, pixels, bits_per_pixel
  169.  
  170.     ' Adjust the coordinate bounds to fit picCanvas.
  171.     AdjustAspect
  172.  
  173.     ' dReaC is the change in the real part
  174.     ' (X value) for C. dImaC is the change in the
  175.     ' imaginary part (Y value).
  176.     wid = picCanvas.ScaleWidth
  177.     hgt = picCanvas.ScaleHeight
  178.     dReaC = (m_Xmax - m_Xmin) / (wid - 1)
  179.     dImaC = (m_Ymax - m_Ymin) / (hgt - 1)
  180.  
  181.     ' Calculate the values.
  182.     ReaC = m_Xmin
  183.     For i = 0 To wid - 1
  184.         ImaC = m_Ymin
  185.         For j = 0 To hgt - 1
  186.             ReaZ = 0
  187.             ImaZ = 0
  188.             ReaZ2 = 0
  189.             ImaZ2 = 0
  190.             clr = 1
  191.             Do While clr < MaxIterations And _
  192.                     ReaZ2 + ImaZ2 < MAX_MAG_SQUARED
  193.                 ' Calculate Z(clr).
  194.                 ReaZ2 = ReaZ * ReaZ
  195.                 ImaZ2 = ImaZ * ImaZ
  196.                 ImaZ = 2 * ImaZ * ReaZ + ImaC
  197.                 ReaZ = ReaZ2 - ImaZ2 + ReaC
  198.                 clr = clr + 1
  199.             Loop
  200.  
  201.             clr = m_Colors(1 + clr Mod NumColors)
  202.             With pixels(i, j)
  203.                 .rgbRed = clr And &HFF&
  204.                 .rgbGreen = (clr And &HFF00&) \ &H100&
  205.                 .rgbBlue = (clr And &HFF0000) \ &H10000
  206.             End With
  207.  
  208.             ImaC = ImaC + dImaC
  209.         Next j
  210.         ReaC = ReaC + dReaC
  211.  
  212.         ' Let the user know we're not dead.
  213.         If i Mod 10 = 0 Then
  214.             picCanvas.Line (0, 0)-(wid, i), vbWhite, BF
  215.             picCanvas.Refresh
  216.         End If
  217.     Next i
  218.  
  219.     ' Update the image.
  220.     SetBitmapPixels picCanvas, bits_per_pixel, pixels
  221.     picCanvas.Refresh
  222.     picCanvas.Picture = picCanvas.Image
  223.  
  224.     Caption = "Mand (" & Format$(m_Xmin) & ", " & _
  225.         Format$(m_Ymin) & ")-(" & _
  226.         Format$(m_Xmax) & ", " & _
  227.         Format$(m_Ymax) & ")"
  228. End Sub
  229. ' Reset the number of colors to 0.
  230. Public Sub ResetColors()
  231.     NumColors = 0
  232.     Erase m_Colors
  233. End Sub
  234. ' Start a rubberband box to select a zoom area.
  235. Private Sub picCanvas_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
  236.     m_DrawingBox = True
  237.     m_StartX = X
  238.     m_StartY = Y
  239.     m_CurX = X
  240.     m_CurY = Y
  241.     picCanvas.DrawMode = vbInvert
  242.     picCanvas.Line (m_StartX, m_StartY)-(m_CurX, m_CurY), , B
  243. End Sub
  244.  
  245.  
  246. ' Continue the zoom area rubberband box.
  247. Private Sub picCanvas_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
  248.     If Not m_DrawingBox Then Exit Sub
  249.     picCanvas.Line (m_StartX, m_StartY)-(m_CurX, m_CurY), , B
  250.     m_CurX = X
  251.     m_CurY = Y
  252.     picCanvas.Line (m_StartX, m_StartY)-(m_CurX, m_CurY), , B
  253. End Sub
  254.  
  255.  
  256. ' Zoom in on the selected area.
  257. Private Sub picCanvas_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
  258. Dim x1 As Single
  259. Dim x2 As Single
  260. Dim y1 As Single
  261. Dim y2 As Single
  262. Dim factor As Single
  263.  
  264.     If Not m_DrawingBox Then Exit Sub
  265.     m_DrawingBox = False
  266.  
  267.     picCanvas.Line (m_StartX, m_StartY)-(m_CurX, m_CurY), , B
  268.     picCanvas.DrawMode = vbCopyPen
  269.     m_CurX = X
  270.     m_CurY = Y
  271.     
  272.     ' Put the coordinates in proper order.
  273.     If m_CurX < m_StartX Then
  274.         x1 = m_CurX
  275.         x2 = m_StartX
  276.     Else
  277.         x1 = m_StartX
  278.         x2 = m_CurX
  279.     End If
  280.     If x1 = x2 Then x2 = x1 + 1
  281.     If m_CurY < m_StartY Then
  282.         y1 = m_CurY
  283.         y2 = m_StartY
  284.     Else
  285.         y1 = m_StartY
  286.         y2 = m_CurY
  287.     End If
  288.     If y1 = y2 Then y2 = y1 + 1
  289.  
  290.     ' Convert screen coords into drawing coords.
  291.     factor = (m_Xmax - m_Xmin) / picCanvas.ScaleWidth
  292.     m_Xmax = m_Xmin + x2 * factor
  293.     m_Xmin = m_Xmin + x1 * factor
  294.  
  295.     factor = (m_Ymax - m_Ymin) / picCanvas.ScaleHeight
  296.     m_Ymax = m_Ymin + y2 * factor
  297.     m_Ymin = m_Ymin + y1 * factor
  298.  
  299.     Screen.MousePointer = vbHourglass
  300.     DrawMandelbrot
  301.     Screen.MousePointer = vbDefault
  302. End Sub
  303.  
  304.  
  305.  
  306. ' Force Visual Basic to resize the bitmap.
  307. Private Sub picCanvas_Resize()
  308.     picCanvas.Cls
  309. End Sub
  310.  
  311.  
  312. ' Save the picture.
  313. Private Sub mnuFileSaveAs_Click()
  314. Dim file_name As String
  315.  
  316.     ' Allow the user to pick a file.
  317.     On Error Resume Next
  318.  
  319.     dlgFile.DialogTitle = "Save As File"
  320.     dlgFile.Flags = cdlOFNOverwritePrompt + cdlOFNHideReadOnly
  321.     dlgFile.ShowSave
  322.     If Err.Number = cdlCancel Then
  323.         Exit Sub
  324.     ElseIf Err.Number <> 0 Then
  325.         Beep
  326.         MsgBox "Error selecting file.", , vbExclamation
  327.         Exit Sub
  328.     End If
  329.     On Error GoTo 0
  330.  
  331.     file_name = Trim$(dlgFile.FileName)
  332.     dlgFile.InitDir = Left$(file_name, Len(file_name) _
  333.         - Len(dlgFile.FileTitle) - 1)
  334.  
  335.     ' Save the picture.
  336.     SavePicture picCanvas.Image, file_name
  337. End Sub
  338.  
  339. ' Draw the initial Mandelbrot set.
  340. Private Sub Form_Load()
  341. Dim i As Integer
  342.  
  343.     Me.Show
  344.     DoEvents
  345.  
  346.     MaxIterations = 64
  347.  
  348.     ' Create some default colors.
  349.     ResetColors
  350.     AddColor frmConfig.picColor(40).BackColor
  351.     For i = 17 To 23
  352.         AddColor frmConfig.picColor(i).BackColor
  353.     Next i
  354.     Unload frmConfig
  355.  
  356.     dlgFile.Filter = "Bitmap Files (*.bmp)|*.bmp|" & _
  357.         "All Files (*.*)|*.*"
  358.     dlgFile.InitDir = App.Path
  359.     dlgFile.CancelError = True
  360.  
  361.     ' Display the first Mandelbrot set.
  362.     mnuScaleFull_Click
  363. End Sub
  364.  
  365. Private Sub Form_Resize()
  366.     picCanvas.Move 0, 0, ScaleWidth, ScaleHeight
  367. End Sub
  368.  
  369.  
  370.  
  371. ' Let the user set program options.
  372. Private Sub mnuOptOptions_Click()
  373.     frmConfig.Initialize Me
  374.     frmConfig.Show vbModal
  375. End Sub
  376.  
  377. ' Zoom out to full scale.
  378. Private Sub mnuScaleFull_Click()
  379.     m_Xmin = MIN_X
  380.     m_Xmax = MAX_X
  381.     m_Ymin = MIN_Y
  382.     m_Ymax = MAX_Y
  383.  
  384.     Screen.MousePointer = vbHourglass
  385.     DrawMandelbrot
  386.     Screen.MousePointer = vbDefault
  387. End Sub
  388.  
  389. ' Make a series of images.
  390. Private Sub MakeMovie(file_name As String)
  391. Dim num_frames As Integer
  392. Dim frame As Integer
  393. Dim fraction As Single  ' Amount to reduce image.
  394. Dim xmid As Single      ' Center of image.
  395. Dim ymid As Single
  396. Dim wid1 As Single      ' Starting dimensions.
  397. Dim hgt1 As Single
  398. Dim wid2 As Single      ' Finishing dimensions.
  399. Dim hgt2 As Single
  400. Dim wid As Single       ' Current dimensions.
  401. Dim hgt As Single
  402.  
  403. Dim start_time As Single
  404. Dim stop_time As Single
  405. Dim max_time As Single
  406. Dim min_time As Single
  407.  
  408. Dim txt As String
  409. Dim value As Integer
  410.  
  411.     ' See how may frames the user wants.
  412.     txt = InputBox("Number of frames:", _
  413.         "Frames", "20")
  414.     If txt = "" Then Exit Sub
  415.     If IsNumeric(txt) Then num_frames = CInt(txt)
  416.     If num_frames < 1 Then num_frames = 20
  417.  
  418.     Screen.MousePointer = vbHourglass
  419.     max_time = 0
  420.     min_time = 100000
  421.  
  422.     ' Set the center of focus and dimensions.
  423.     xmid = (m_Xmin + m_Xmax) / 2
  424.     ymid = (m_Ymin + m_Ymax) / 2
  425.     wid1 = MAX_X - MIN_X
  426.     wid2 = m_Xmax - m_Xmin
  427.  
  428.     ' Compute start and finish heights.
  429.     hgt1 = wid1 * picCanvas.ScaleHeight / picCanvas.ScaleWidth
  430.     hgt2 = wid2 * picCanvas.ScaleHeight / picCanvas.ScaleWidth
  431.  
  432.     ' Compute the amount to reduce the image for
  433.     ' each frame.
  434.     fraction = Exp(Log(wid2 / wid1) / (num_frames - 1))
  435.  
  436.     ' Start cranking out frames.
  437.     wid = wid1
  438.     hgt = hgt1
  439.     For frame = 0 To num_frames - 1
  440.         Caption = "Mand " & Str$(frame) & _
  441.             "/" & Format$(num_frames - 1)
  442.         m_Xmin = xmid - wid / 2
  443.         m_Xmax = xmid + wid / 2
  444.         m_Ymin = ymid - hgt / 2
  445.         m_Ymax = ymid + hgt / 2
  446.  
  447.         start_time = Timer
  448.         DrawMandelbrot
  449.         stop_time = Timer
  450.  
  451.         If min_time > stop_time - start_time Then min_time = stop_time - start_time
  452.         If max_time < stop_time - start_time Then max_time = stop_time - start_time
  453.  
  454.         SavePicture picCanvas.Image, _
  455.             file_name & Format$(frame) & ".bmp"
  456.         Beep
  457.         DoEvents
  458.  
  459.         wid = wid * fraction
  460.         hgt = hgt * fraction
  461.     Next frame
  462.  
  463.     Screen.MousePointer = vbDefault
  464.  
  465.     MsgBox _
  466.         "Longest:  " & Format$(max_time, "0.00") & _
  467.             " seconds." & vbCrLf & _
  468.         "Shortest: " & Format$(min_time, "0.00") & _
  469.             " seconds." & vbCrLf
  470. End Sub
  471. ' Make a series of images.
  472. Private Sub mnuMovieCreate_Click()
  473. Dim old_file_name As String
  474. Dim file_name As String
  475. Dim pos As Integer
  476.  
  477.     ' Allow the user to pick a file.
  478.     On Error Resume Next
  479.     old_file_name = dlgFile.FileName
  480.     dlgFile.DialogTitle = "Select base file name (no number)"
  481.     dlgFile.Flags = cdlOFNOverwritePrompt + cdlOFNHideReadOnly
  482.  
  483.     pos = InStr(old_file_name, ".")
  484.     If pos > 0 Then old_file_name = Left$(old_file_name, pos - 1)
  485.     dlgFile.FileName = old_file_name
  486.  
  487.     dlgFile.ShowSave
  488.     If Err.Number = cdlCancel Then
  489.         dlgFile.FileName = old_file_name
  490.         Exit Sub
  491.     ElseIf Err.Number <> 0 Then
  492.         dlgFile.FileName = old_file_name
  493.         MsgBox "Error selecting file.", , vbExclamation
  494.         Exit Sub
  495.     End If
  496.     On Error GoTo 0
  497.     
  498.     file_name = Trim$(dlgFile.FileName)
  499.     dlgFile.FileName = old_file_name
  500.     dlgFile.InitDir = Left$(file_name, Len(file_name) _
  501.         - Len(dlgFile.FileTitle) - 1)
  502.  
  503.     ' Trim off the extension if any.
  504.     pos = InStr(file_name, ".")
  505.     If pos > 0 Then file_name = Left$(file_name, pos - 1)
  506.     
  507.     ' Add a trailing underscore if needed.
  508.     If Right$(file_name, 1) <> "_" Then _
  509.         file_name = file_name & "_"
  510.     
  511.     ' Make the movie.
  512.     MakeMovie file_name
  513. End Sub
  514. ' Increase the area shown by a factor of Index.
  515. Private Sub mnuScale_Click(Index As Integer)
  516. Dim size As Single
  517. Dim mid As Single
  518.  
  519.     size = Index * (m_Xmax - m_Xmin)
  520.     If size > 3.2 Then
  521.         mnuScaleFull_Click
  522.         Exit Sub
  523.     End If
  524.     mid = (m_Xmin + m_Xmax) / 2
  525.     m_Xmin = mid - size / 2
  526.     m_Xmax = mid + size / 2
  527.     
  528.     size = Index * (m_Ymax - m_Ymin)
  529.     If size > 2.4 Then
  530.         mnuScaleFull_Click
  531.         Exit Sub
  532.     End If
  533.     mid = (m_Ymin + m_Ymax) / 2
  534.     m_Ymin = mid - size / 2
  535.     m_Ymax = mid + size / 2
  536.     
  537.     Screen.MousePointer = vbHourglass
  538.     DrawMandelbrot
  539.     Screen.MousePointer = vbDefault
  540. End Sub
  541.  
  542.